package com.shop.admin.messageHadnle;

import com.alibaba.fastjson.JSONObject;
import com.shop.admin.mapper.DiscountMapper;
import com.shop.admin.mapper.DiscountPreMapper;
import com.shop.admin.model.po.DiscountPre;
import com.shop.ex.ShoppingException;
import com.shop.mapper.MessageMapper;
import com.shop.po.Discount;
import com.shop.po.Message;
import com.shop.service.MessageProcessAbstract;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author 'banxia'
 * @version 1.0
 * @description TODO
 * @date 2023/2/27 13:50
 */
@Component
@Slf4j
public class DiscountPublishHandle extends MessageProcessAbstract {

    @Autowired
    private DiscountMapper discountMapper;

    @Autowired
    private DiscountPreMapper discountPreMapper;

    //用于重新定义sql语句
    @Autowired
    private MessageMapper messageMapper;

    @Autowired
    private StringRedisTemplate redisTemplate;

    private static final long  expireTime=1000*60*60*24;//redis有效期一天

    //这个要在xxl平台上注册
    //并且本项目默认该名称和消息表的type相同
    @XxlJob(("discountPublish"))
    public void discountPublishTask(){
        //分片索引/总数
        int shardIndex = XxlJobHelper.getShardIndex();
        int shardTotal = XxlJobHelper.getShardTotal();
        //这里设置为取出全部信息，（比较快）
        process(shardIndex,shardTotal,"discountPublish",Integer.MAX_VALUE,1000*60);
    }

    SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    //对sql语句的重新定义,获取信息的时候先判断是否到达时间
    @Override
    public List<Message> getMessages(int shardIndex, int shardTotal, String messageType, int count){
        String now = format.format(new Date());
        List<Message> list=messageMapper.discountPublishMessage(shardIndex, shardTotal, messageType, count, now);
        return list;
    }



    //各个任务分别执行，这里不需要保证全部任务的一致性！！！
    //这里message信息如下：
    // key1存储discount_pre的id
    // key2存储discount_publish_time可以保证取出来的数据是到达发布时间的
    // key3储存discount的id，方便读出用于redis缓存
    //会达到最终的一致性
    @Override
    public boolean execute(Message mqMessage) {
        //第一阶段----发放优惠券到discount表中
        boolean b = executeOne(mqMessage);
        if (b) {
            //完成第一阶段任务
            getMqMessageService().completedStageOne(mqMessage.getId());
        }else{
            log.error("第一阶段任务完成失败-----");
            return false;
        }
        //第二阶段---将该优惠券储存到redis中
        b=executeTwe(mqMessage);
        return true;
    }



    //第一阶段任务-->将代发放的优惠券发放,之后更新两张表
    @Transactional
    public boolean executeOne(Message mqMessage){
        String key1=mqMessage.getBusinessKey1();
        DiscountPre discountPre = discountPreMapper.selectById(Long.parseLong(key1));
        Discount newDiscount = new Discount();
        BeanUtils.copyProperties(discountPre,newDiscount);
        //这里要特别设置discount的id为null。因为两张表的id是不一样的（可能）。
        newDiscount.setId(null);
        //执行异常--->这里并未登录用户，所以在注入admin的时候会失败--->已解决
        int j = discountMapper.insert(newDiscount);
        if (j == 0) {
            ShoppingException.ThrowShoppingException("将待发布优惠券发布失败。。");
        }
        //这里需要给message添加新的数据！因为redis要查询根据id查优惠券
        Message updateMessagpe = new Message();
        updateMessagpe.setId(mqMessage.getId());
        updateMessagpe.setBusinessKey3(newDiscount.getId().toString());
        mqMessage.setBusinessKey3(updateMessagpe.getBusinessKey3());
        //更新消息表
        boolean b = getMqMessageService().updateById(updateMessagpe);
        if (!b){
            ShoppingException.ThrowShoppingException("优惠券发布失败\n---消息key2更新失败");
        }
        return true;
    }


    //将该优惠券存储到redis----便于抢券不会超卖
    //这里的key1
    public boolean executeTwe(Message message){
        try {
            String key2 = message.getBusinessKey3();
            Discount discount = discountMapper.selectById(Long.parseLong(key2));
            String valueJson = JSONObject.toJSONString(discount);
            String redisKeyPre="discount:publish:";
            redisTemplate.opsForValue().set(redisKeyPre+discount.getId(),valueJson,expireTime, TimeUnit.SECONDS);
            //删除待发布表信息
            int i = discountPreMapper.deleteById(message.getBusinessKey1());
            if (i == 0) {
                ShoppingException.ThrowShoppingException("删除待发布表信息失败。。");
            }
        } catch (Exception e) {
            log.error("缓存到redis出异常");
//            ShoppingException.ThrowShoppingException("第二阶段缓存到redis出异常");
            return false;
        }
        return true;
    }


}
